package trans.service;

import java.util.Date;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.DateFormatUtils;
import org.apache.commons.lang.time.DateUtils;
import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Restrictions;

import trans.action.support.PageMode;
import trans.model.AirSa;
import trans.model.Gatway;
import trans.model.OceanSa;
import trans.model.Sa;
import trans.model.SaStateHis;
import trans.model.User;
import trans.support.Constants;
import trans.utils.HibernateUtil;


public class SADAO {
	//TODO 需要测试下事务的隔离级别
	public static boolean saveSA(Sa sa,User creator) throws Exception{
		  Session s = null;   
	      Transaction tx = null;   
	      try {   
	            s = HibernateUtil.getSession();   
	            tx = s.beginTransaction();   
	            
	            String saNo = genSANO(sa.getClientId(),sa.getGatwayId());
	            sa.setSaNo(saNo);
	            sa.setCreateTime(new Date());
	            sa.setCreateBy_id(creator.getId());
	            sa.setStatus(Constants.STATUS_ENABLE);
	            sa.setFlagRead(Constants.STATUS_SA_NONE);
	            s.saveOrUpdate(sa);
	            
	        	SaStateHis his = new SaStateHis();
	    		his.setCreateBy_id(creator.getId());
	    		Date createTime =
            		DateUtils.parseDate(sa.getStateChangeTime(), new String[]{"yyyy-MM-dd HH:mm"});
	    		his.setCreateTime(createTime);
	    		his.setStateFrom(null);
	    		his.setStateTo(sa.getState());
	    		his.setSaId(sa.getId());
	    		
	    		if(his.getStateTo() != Constants.AIRSA_STATUS_DLV || StringUtils.isNotBlank(his.getRelativeStation())){
	    			HibernateUtil.saveOrUpdate(his);
	    		}
	    		tx.commit();   
	      } finally {   
	           if (s != null)   
	                s.close();   
	      }  
		return true;
	}
	
	public static void addSAStateHis(User creator,Integer saId,Date stateChangeTime,String relativeStation,String relativeFlightNo){
	  	SaStateHis his = new SaStateHis();
		his.setCreateBy_id(creator.getId());
		his.setCreateTime(stateChangeTime);
		his.setStateFrom(Constants.AIRSA_STATUS_DLV);
		his.setStateTo(Constants.AIRSA_STATUS_DLV);
		his.setSaId(saId);
		his.setRelativeStation(relativeStation);
		his.setRelativeFlightNo(relativeFlightNo);
		HibernateUtil.saveOrUpdate(his);
	}
	
	//FUL 11068001 = FUL(3 LETTER CODE) +  11��06�� + HK(08) + 3λ����(001)
	private static String genSANO(Integer clientId, Integer gatwayId){
		 Gatway gatway = (Gatway) HibernateUtil.getSession().get(Gatway.class,gatwayId);
		 
		String gatwayName = gatway.getName();
		User client = (User) HibernateUtil.getSession().get(User.class, clientId);
		String clientCode = client.getUserCode();
		String directCode = gatway.getDirectCode();
		
		Integer currentMonth = Integer.parseInt(DateFormatUtils.format(new Date(), "M"));
		if(gatway.getNativeMonth().equals(currentMonth) == false){
			gatway.setNativeIndex(0);
			gatway.setNativeMonth(currentMonth);
			HibernateUtil.saveOrUpdate(gatway);
		}
		
		Integer intIndex = gatway.getNativeIndex()+1 ;
		String indexValue = "";
		switch (intIndex.toString().length()) {
		case 1:
			indexValue = "00" + intIndex;
			break;
		case 2:
			indexValue = "0" + intIndex;
			break;
		case 3:
			indexValue = "" + intIndex;
			break;
		default:
			throw new RuntimeException("SANO Index TO Long for Gatway" + gatwayName);
		}
		
		String day = DateFormatUtils.format(new Date(), Constants.getSANODate());
		
		gatway.setNativeIndex(intIndex);
		
		HibernateUtil.saveOrUpdate(gatway);
		
		return 
			String.format(Constants.getSANOFormat(), new Object[]{clientCode,day,directCode,indexValue});
	}
	
	public static void updateSA(Sa sa) throws Exception{
		HibernateUtil.saveOrUpdate(sa);
	}
	
	public static boolean updateSA(Sa sa,User excutor) throws Exception{
		  Session s = null;   
	      Transaction tx = null;   
	      try {   
	            s = HibernateUtil.getSession();   
	            tx = s.beginTransaction();   
	            
	            if(sa.getSaOlderState().equals((sa.getState())) == false){
	            	Date changeTime =
	            		DateUtils.parseDate(sa.getStateChangeTime(), new String[]{"yyyy-MM-dd HH:mm"});
	            	addSaHis(sa.getId(),sa.getSaOlderState(),sa.getState(),excutor,changeTime);
	            }
	            sa.setCreateTime(new Date());
	            s.saveOrUpdate(sa);
	            
	            tx.commit();   
	      } finally {   
	           if (s != null)   
	                s.close();   
	      }  
		return true;
	}

	@SuppressWarnings("unchecked")
	private static void addSaHis(Integer saId,Integer saOlderState, Integer newState, User excutor,Date changeTime) {
		SaStateHis his = new SaStateHis();
		
		if(saOlderState > newState){
			Criteria criteria =
				 HibernateUtil.getSession().createCriteria(SaStateHis.class);
			criteria.add(Restrictions.eq(SaStateHis.PROP_SA_ID,saId));
			List<SaStateHis> hises = criteria.list();
			for(SaStateHis each:hises){
				if(each.getStateTo() >= newState){
					HibernateUtil.delete(each);
				}
			}
			his.setStateFrom(null);
		}else{
			his.setStateFrom(saOlderState);
		}
		his.setCreateBy_id(excutor.getId());
		his.setCreateTime(changeTime);
		his.setStateTo(newState);
		his.setSaId(saId);
		
		if(his.getStateTo() != Constants.AIRSA_STATUS_DLV || StringUtils.isNotBlank(his.getRelativeStation())){
			HibernateUtil.saveOrUpdate(his);
		}
	}

	@SuppressWarnings("unchecked")
	public static void fillSaPage(PageMode pm) {
		Class<?> searchClass = null;
		if(pm.getParam(Sa.PROP_SATYPE).equals(Constants.SATYPE_AIR)){
			searchClass = AirSa.class;
		}else if(pm.getParam(Sa.PROP_SATYPE).equals(Constants.SATYPE_OCEAN)){
			searchClass = OceanSa.class;
		}else if(pm.getParam(Sa.PROP_SATYPE).equals(Constants.SATYPE_ALL)){
			searchClass = Sa.class;
		}
		
		Criteria criteria =
			 HibernateUtil.getSession().createCriteria(searchClass);
		
		
		Integer userId = (Integer) pm.getParam(Sa.PROP_CLIENT_ID);
		Integer status = (Integer) pm.getParam(Sa.PROP_STATUS);
		Integer isPendding = (Integer) pm.getParam(Sa.PROP_IS_PENDDING);
		String saNo = (String) pm.getParam(Sa.PROP_SA_NO);
		
		if(userId != null){
			criteria.add(Restrictions.eq(Sa.PROP_CLIENT_ID, userId) );
		}
		if(status != null){
			criteria.add(Restrictions.eq(Sa.PROP_STATUS, status) );
		}
		if(isPendding != null){
			criteria.add(Restrictions.eq(Sa.PROP_IS_PENDDING, isPendding) );
		}
		if(StringUtils.isNotEmpty(saNo)){
			criteria.add(Restrictions.like(Sa.PROP_SA_NO, "%"+saNo.trim()+"%") );
		}
		
		criteria.setFirstResult(pm.getOffset());
		criteria.setMaxResults(pm.getMaxPageItems());
		
		if(pm.getParam(Sa.PROP_SATYPE).equals(Constants.SATYPE_AIR)){
			criteria.addOrder(Order.desc(Sa.PROP_FLIGHT_DATE));
			criteria.addOrder(Order.desc(Sa.PROP_MAWB_NO));
			criteria.addOrder(Order.desc(Sa.PROP_HAWB_NO));
		}else if(pm.getParam(Sa.PROP_SATYPE).equals(Constants.SATYPE_OCEAN)){
			criteria.addOrder(Order.desc(Sa.PROP_VESSEL_DATE));
			criteria.addOrder(Order.desc(Sa.PROP_BL_NO));
			criteria.addOrder(Order.desc(Sa.PROP_HBL));
		}
		
		pm.setDatas(criteria.list());
		
		criteria =  HibernateUtil.getSession().createCriteria(searchClass); 
		if(userId != null){
			criteria.add(Restrictions.eq(Sa.PROP_CLIENT_ID, userId) );
		}
		if(status != null){
			criteria.add(Restrictions.eq(Sa.PROP_STATUS, status) );
		}
		if(isPendding != null){
			criteria.add(Restrictions.eq(Sa.PROP_IS_PENDDING, isPendding) );
		}
		if(StringUtils.isNotEmpty(saNo)){
			criteria.add(Restrictions.like(Sa.PROP_SA_NO, "%"+saNo.trim()+"%") );
		}
		Long count = 
			(Long) criteria.setProjection(Projections.rowCount()).uniqueResult(); 
		pm.setTotal(count);
	}
	
	@SuppressWarnings("unchecked")
	public static void fillSaPageByHandStatus(PageMode pm) {
		Class<?> searchClass = null;
		if(pm.getParam(Sa.PROP_SATYPE).equals(Constants.SATYPE_AIR)){
			searchClass = AirSa.class;
		}else if(pm.getParam(Sa.PROP_SATYPE).equals(Constants.SATYPE_OCEAN)){
			searchClass = OceanSa.class;
		}else if(pm.getParam(Sa.PROP_SATYPE).equals(Constants.SATYPE_ALL)){
			searchClass = Sa.class;
		}
		
		Criteria criteria =
			 HibernateUtil.getSession().createCriteria(searchClass);
		Integer userId = (Integer) pm.getParam(Sa.PROP_CLIENT_ID);
		Integer status = (Integer) pm.getParam(Sa.PROP_STATUS);
		Integer handStatus = (Integer) pm.getParam(Sa.PROP_FLAG_READ);
		
		if(userId != null){
			criteria.add(Restrictions.eq(Sa.PROP_CLIENT_ID, userId) );
		}
		criteria.add(Restrictions.eq(Sa.PROP_STATUS, status));
		criteria.add(Restrictions.eq(Sa.PROP_FLAG_READ, handStatus));
		
		criteria.setFirstResult(pm.getOffset());
		criteria.setMaxResults(pm.getMaxPageItems());
		
		if(pm.getParam(Sa.PROP_SATYPE).equals(Constants.SATYPE_AIR)){
			criteria.addOrder(Order.desc(Sa.PROP_FLIGHT_DATE));
		}else if(pm.getParam(Sa.PROP_SATYPE).equals(Constants.SATYPE_OCEAN)){
			criteria.addOrder(Order.desc(Sa.PROP_VESSEL_DATE));
		}
		
		pm.setDatas(criteria.list());
		
		criteria =  HibernateUtil.getSession().createCriteria(searchClass); 
		if(userId != null){
			criteria.add(Restrictions.eq(Sa.PROP_CLIENT_ID, userId) );
		}
		criteria.add(Restrictions.eq(Sa.PROP_STATUS, status));
		criteria.add(Restrictions.eq(Sa.PROP_FLAG_READ, handStatus));
		Long count = 
			(Long) criteria.setProjection(Projections.rowCount()).uniqueResult(); 
		pm.setTotal(count);
	}

	public static void updateSaStatus(Integer editSaId, Integer updateStatus) {
		Sa sa = getSa(editSaId);
		sa.setStatus(updateStatus);
		sa.setCreateTime(new Date());
		HibernateUtil.saveOrUpdate(sa);
	}

	public static Sa getSa(Integer editSaId) {
		Sa sa =
			(Sa) HibernateUtil.get(Sa.class, editSaId);
		sa.setSaOlderState(sa.getState());
		if(sa instanceof AirSa){
			((AirSa)sa).splitAwb();
		}
		return sa;
	}
	
	public static long getSaCountByHandStatus(Integer userId,Integer handStatus){
		Criteria criteria =
			HibernateUtil.getSession().createCriteria(Sa.class);
		if(userId != null){
			criteria.add(Restrictions.eq(Sa.PROP_CLIENT_ID, userId) );
		}
		criteria.add(Restrictions.eq(Sa.PROP_STATUS, Constants.STATUS_ENABLE));
		criteria.add(Restrictions.eq(Sa.PROP_FLAG_READ, handStatus) );
		Long count = 
			(Long) criteria.setProjection(Projections.rowCount()).uniqueResult();
		return count;
	}

}
